package protocol

import (
	"net"
	"runtime"
	"strings"

	"github.com/nsqio/nsq/internal/lg"
)

type TCPHandler interface {
	Handle(net.Conn)
}

// 本方法开始接受客户端连接，并注册处理方法
func TCPServer(listener net.Listener, handler TCPHandler, logf lg.AppLogFunc) {
	logf(lg.INFO, "TCP: listening on %s", listener.Addr())

	for {
		clientConn, err := listener.Accept()
		if err != nil {
			if nerr, ok := err.(net.Error); ok && nerr.Temporary() {
				logf(lg.WARN, "temporary Accept() failure - %s", err)
				// 如果发生临时的error让出时间片。猜想这么做的原因可能是当前网络状况不好引起的一些临时error，如果马上去accept，会得到另外一个error，不如让出时间片，让其他goroutine 做事情。
				runtime.Gosched()
				continue
			}
			// theres no direct way to detect this error because it is not exposed
			if !strings.Contains(err.Error(), "use of closed network connection") {
				logf(lg.ERROR, "listener.Accept() - %s", err)
			}
			break
		}
		//handler由调用时通过参数传入,作为工具方法，将可能的变化放在外部，以保证本方法可以有尽可能多的适用范围
		go handler.Handle(clientConn)
	}

	logf(lg.INFO, "TCP: closing %s", listener.Addr())
}
